https://segmentfault.com/a/11...
原型 / 构造函数 / 实例
- 对原型的理解
我们知道在es6之前,js没有类和继承的概念,js是通过原型来实现继承的。在js中一个构造函数默认自带有一个prototype属性, 这个的属性值是一个对象,同时这个prototype对象自带有一个constructor属性,这个属性指向这个构造函数,同时每一个实例 都有一个__proto__属性指向这个prototype对象,我们可以将这个叫做隐式原型,我们在使用一个实例的方法的时候,会先检查 这个实例中是否有这个方法,没有则会继续向上查找这个prototype对象是否有这个方法,刚刚我们说到prototype是一个对象, 那么也即是说这个是一个对象的实例,那么这个对象同样也会有一个__proto__属性指向对象的prototype对象。
原型链
执行上下文(EC)
变量对象
- javascript有哪些方法定义对象
对象字面量: var obj = {};
构造函数: var obj = new Object();
Object.create(): var obj = Object.create(Object.prototype);
作用域
作用域链
作用域链的原理和原型链很类似,如果这个变量在自己的作用域中没有,那么它会寻找父级的,直到最顶层。
注意:JS没有块级作用域,若要形成块级作用域,可通过(function(){})();立即执行的形式实现。
闭包
闭包指的是一个函数可以访问另一个函数作用域中变量。常见的构造方法,是在一个函数内部定义另外一个函数。内部函数可以引用外层的变量;外层变量不会被垃圾回收机制回收。
注意,闭包的原理是作用域链,所以闭包访问的上级作用域中的变量是个对象,其值为其运算结束后的最后一个值。
优点:避免全局变量污染。缺点:容易造成内存泄漏。
例子:
function makeFunc() {
var name = "Mozilla";
function displayName() {
console.log(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc(); //输出Mozilla
myFunc 变成一个 闭包。闭包是一种特殊的对象。它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。在我们的例子中,myFunc 是一个闭包,由 displayName 函数和闭包创建时存在的 "Mozilla" 字符串形成。
script引入方式
对象的拷贝
这道题考察了以下知识点:
使用 typeof 判断值得类型;
使用 toString 区分数组和对象;
递归函数的使用;
- 实现一个函数 clone(),可以对 JavaScript 中的5种主要的数据类型(包括 Number、String、Object、Array、Boolean)进行值复制。
function clone(obj) {
//判断是对象,就进行循环复制
if (typeof obj === 'object' && typeof obj !== 'null') {
// 区分是数组还是对象,创建空的数组或对象
var o = Object.prototype.toString.call(obj).slice(8, -1) === "Array" ? [] : {};
for (var k in obj) {
// 如果属性对应的值为对象,则递归复制
if(typeof obj[k] === 'object' && typeof obj[k] !== 'null'){
o[k] = clone(obj[k])
}else{
o[k] = obj[k];
}
}
}else{ //不为对象,直接把值返回
return obj;
}
return o;
}
new运算符的执行过程
1) 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
2) 属性和方法被加入到 this 引用的对象中。
3) 新创建的对象由 this 所引用,并且最后隐式的返回 this 。
使用new操作符实例化一个对象的具体步骤
1.构造一个新的对象
2.将构造函数的作用域赋给新对象(也就是说this指向了新的对象)
3.执行构造函数中的代码
4.返回新对象
instanceof原理
代码的复用
继承
其他问题
- Javascript实现继承的几种方式:JavaScript实现类与继承的方法(全面整理)
js数据类型
其他问题
- typeof 返回哪些数据类型
typeof 返回七种值:
“number”、“string”、“boolean”、“object”、"symbol"、“function”和“undefined”。
typeof undefined、null、NaN分别返回undefined,object,number
- JavaScript有几种类型的值?你能画一下他们的内存图吗?
基本数据类型存储在栈中,引用数据类型(对象)存储在堆中,指针放在栈中。
两种类型的区别是:存储位置不同;原始数据类型直接存储在栈中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;引用数据类型存储在堆中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
- 栈和堆的区别
栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;
堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释放。
类型转换
- 对象到数字的转换步骤
- 如果对象有valueOf()方法并且返回元素值,javascript将返回值转换为数字作为结果
- 否则,如果对象有toString()并且返回原始值,javascript将返回结果转换为数字作为结果
- 否则,throws a TypeError
- 对象到字符串的转换步骤
1.如果对象有toString()方法,javascript调用它。如果返回一个原始值(primitive value如:string number boolean),将这个值转换为字符串作为结果
2.如果对象没有toString()方法或者返回值不是原始值,javascript寻找对象的valueOf()方法,如果存在就调用它,返回结果是原始值则转为字符串作为结果
3.否则,javascript不能从toString()或者valueOf()获得一个原始值,此时throws a TypeError
类型判断
- javascript做类型判断的方法有哪些?
typeof、instanceof 、 Object.prototype.toString()(待续)
- 实现一个类型判断函数,需要鉴别出基本类型、function、null、NaN、数组、对象?
只需要鉴别这些类型那么使用typeof即可,要鉴别null先判断双等判断是否为null,之后使用typeof判断,如果是obejct的话,再用Array.isArray判断 是否为数组,如果是数字再使用isNaN判断是否为NaN,(需要注意的是NaN并不是JavaScript数据类型,而是一种特殊值)如下:
function type(ele) {
if(ele===null) {
return null;
} else if(typeof ele === 'object') {
if(Array.isArray(ele)) {
return 'array';
} else {
return typeof ele;
}
} else if(typeof ele === 'number') {
if(isNaN(ele)) {
return NaN;
} else {
return typeof ele;
}
} else{
return typeof ele;
}
}
模块化
- 对js模块化的理解
在ES6出现之前,js没有标准的模块化概念,这也就造成了js多人写作开发容易造成全局污染的情况,以前我们可能会采用立即执行 函数、对象等方式来尽量减少变量这种情况,后面社区为了解决这个问题陆续提出了AMD规范和CMD规范,这里不同于Node.js的 CommonJS的原因在于服务端所有的模块都是存在于硬盘中的,加载和读取几乎是不需要时间的,而浏览器端因为加载速度取决于网速, 因此需要采用异步加载,AMD规范中使用define来定义一个模块,使用require方法来加载一个模块,现在ES6也推出了标准的模块 加载方案,通过export和import来导出和导入模块。
- 模块化开发怎么做
模块化开发指的是在解决某一个复杂问题或者一系列问题时,依照一种分类的思维把问题进行系统性的分解。模块化是一种将复杂系统分解为代码结构更合理,可维护性更高的可管理的模块方式。对于软件行业:系统被分解为一组高内聚,低耦合的模块。
(1)定义封装的模块
(2)定义新模块对其他模块的依赖
(3)可对其他模块的引入支持。在JavaScript中出现了一些非传统模块开发方式的规范。 CommonJS的模块规范,AMD(Asynchronous Module Definition),CMD(Common Module Definition)等。AMD是异步模块定义,所有的模块将被异步加载,模块加载不影响后边语句运行。
- 如何实现一个JS的AMD模块加载器
AMD是解决JS模块化的规范,实现这样的一个模块加载器的关键在于解决每个模块依赖的解析。首先我们需要有一个模块的入口,也就是主模块,比如我们使用 一个use方法作为入口,之后以数组的形式列出了主模块的依赖,这时候我们要想到的是如何解析这一个一个的依赖,也就是如何解析出一个个js文件的绝对地址, 我们可以制定一个规则,如默认为主模块的路径为基准,也可以像requirejs一样使用一个config方法来指定一个baseurl和为每一个模块指定一个path,最后就是 模块的问题,我们需要暴露一个define方法来定义模块,也就是模块名,依赖以及每个模块的各自代码。其中每个模块的代码都应该在依赖加载完之后执行,这就是一个 回调函数,模块的依赖、回调函数、状态、名字、模块导出等可以看做是一个模块的属性,因此我们可以使用一个对象来保存所有的模块,然后每个模块的各个属性存放在一个对象中。 最后我们来考虑一下模块加载的问题,上面我们说到use方法,use方法的逻辑就是遍历依赖,然后对每个模块进行加载,也就是解析地址然后使用插入script,我们假设 使用loadModule方法来加载依赖,那么这个函数的逻辑就应该是检查我们的模块是否已经加载过来判断是否需要加载,如果这个模块还有依赖则调用use方法继续解析,模块依赖中我们 还没有提到的问题就是每个模块的依赖是需要被传进模块里来使用的,解决方法就是每个模块的callback方法执行后的返回的export记录下来然后使用apply之类的方法将这些参数传递进去。 大致就是这样子的。
参考:
动手实现一个AMD模块加载器(一)
动手实现一个AMD模块加载器(二)
动手实现一个AMD模块加载器(三)
防抖和节流
函数节流就是让一个函数无法在很短的时间间隔内连续调用,而是间隔一段时间执行,这在我们为元素绑定一些事件的时候经常会用到,比如我们 为window绑定了一个resize事件,如果用户一直改变窗口大小,就会一直触发这个事件处理函数,这对性能有很大影响。
什么是函数节流?
前端面试查漏补缺--(一) 防抖和节流
函数执行改变this
- 谈谈对this对象的理解
1) this总是指向函数的直接调用者(而非间接调用者)
2) 如果有new关键字,this指向new出来的那个对象
3) 在事件中,this指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window。
ES6/ES7
- 简要介绍ES6
ES6在变量的声明和定义方面增加了let、const声明变量,有局部变量的概念,赋值中有比较吸引人的结构赋值,同时ES6对字符串、 数组、正则、对象、函数等拓展了一些方法,如字符串方面的模板字符串、函数方面的默认参数、对象方面属性的简洁表达方式,ES6也 引入了新的数据类型symbol,新的数据结构set和map,symbol可以通过typeof检测出来,为解决异步回调问题,引入了promise和 generator,还有最为吸引人了实现Class和模块,通过Class可以更好的面向对象编程,使用模块加载方便模块化编程,当然考虑到 浏览器兼容性,我们在实际开发中需要使用babel进行编译。
- let、const、var的使用区别
let: 相当于var,用于声明一个变量,在块级作用域有效(可解决for循环问题);不能重复声明;不会变量提升;不会预处理
const: 用于定义一个常量,不能修改,其他特点等同于let,用于保存不用改变的数据
- Map与普通对象的区别
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
AST
babel编译原理
函数柯里化
数组
- 判断数组
Array.isArray([]); // true
Array.isArray(undefined); // false;
或者
array instanceof Array; // true 检测对象的原型链是否指向构造函数的prototype对象
或者
array.constructor === Array; // true
终极大招:
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
注意:typeof []; // "object" 不可以用此方法检查!!!
null,undefined的区别
null表示一个对象被定义了,但存放了空指针,转换为数值时为0。
undefined表示声明的变量未初始化,转换为数值时为NAN。
typeof(null) -- object;
typeof(undefined) -- undefined
["1", "2", "3"].map(parseInt) 答案是多少
[1,NaN,NaN]
解析:
Array.prototype.map()
array.map(callback[, thisArg])
callback函数的执行规则
参数:自动传入三个参数
currentValue(当前被传递的元素);
index(当前被传递的元素的索引);
array(调用map方法的数组)
parseInt方法接收两个参数
第三个参数["1", "2", "3"]将被忽略。parseInt方法将会通过以下方式被调用
parseInt("1", 0)
parseInt("2", 1)
parseInt("3", 2)
parseInt的第二个参数radix为0时,ECMAScript5将string作为十进制数字的字符串解析;
parseInt的第二个参数radix为1时,解析结果为NaN;
parseInt的第二个参数radix在2—36之间时,如果string参数的第一个字符(除空白以外),不属于radix指定进制下的字符,解析结果为NaN。
parseInt("3", 2)执行时,由于"3"不属于二进制字符,解析结果为NaN。
关于事件,IE与火狐的事件机制有什么区别? 如何阻止冒泡?
IE为事件冒泡,Firefox同时支持事件捕获和事件冒泡。但并非所有浏览器都支持事件捕获。jQuery中使用event.stopPropagation()方法可阻止冒泡;(旧IE的方法 ev.cancelBubble = true;)
如何阻止事件冒泡和默认事件?
标准的DOM对象中可以使用事件对象的stopPropagation()方法来阻止事件冒泡,但在IE8以下中IE的事件对象通过设置事件对象的cancelBubble属性为true来阻止冒泡; 默认事件的话通过事件对象的preventDefault()方法来阻止,而IE通过设置事件对象的returnValue属性为false来阻止默认事件。
javascript 代码中的"use strict";是什么意思 ? 使用它区别是什么?
除了正常模式运行外,ECMAscript添加了第二种运行模式:“严格模式”。
作用:
1) 消除js不合理,不严谨地方,减少怪异行为
2) 消除代码运行的不安全之处,
3) 提高编译器的效率,增加运行速度
4) 为未来的js新版本做铺垫。
对JSON的了解
全称:JavaScript Object Notation
JSON中对象通过“{}”来标识,一个“{}”代表一个对象,如{“AreaId”:”123”},对象的值是键值对的形式(key:value)。JSON是JS的一个严格的子集,一种轻量级的数据交换格式,类似于xml。数据格式简单,易于读写,占用带宽小。
两个函数:
JSON.parse(str)
解析JSON字符串 把JSON字符串变成JavaScript值或对象
JSON.stringify(obj)
将一个JavaScript值(对象或者数组)转换为一个 JSON字符串
eval('('+json+')')
用eval方法注意加括号 而且这种方式更容易被攻击
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。